Nicole Hamler

"On my honor, as a student, I have neither given nor received unauthorized aid on this academic work."

Geospatial Analysis using GeoPandas - Part 3

In [6]:
%matplotlib inline

from __future__ import (absolute_import, division, print_function)
import os

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

import seaborn as sns
plt.style.use('bmh')

import pandas as pd
import geopandas as gpd
from geopandas import GeoSeries, GeoDataFrame
from geopandas.tools import sjoin

from shapely.geometry import Point, LineString, Polygon
In [7]:
# ROAD MAP DATASET  (naturalearthdata.com)
rd = gpd.read_file("data\\ne_10m_roads.shp")

(cont. from Part 2)

13. Interactive maps - Bokeh

In [8]:
# Importing Bokeh libraries 
from bokeh.plotting import figure, save
from bokeh.io import output_notebook, show
output_notebook()
from bokeh.plotting import figure, output_file, show
from bokeh.models import GeoJSONDataSource
Loading BokehJS ...
In [9]:
# Initialize plot (p) and assign title
p = figure(title="Hello World")
p
Out[9]:
Figure(
id = 'a7f34976-185f-4027-91c7-5d4a5b7a0b8e', …)

a) Using ColumnDataSource as geo source

In [10]:
# Importing ColumnDataSource to allow Bokeh to read and store the data
from bokeh.models import ColumnDataSource
In [53]:
# Unlike Shapely, Bokeh can't read files which have geometry objects 
inter = gpd.read_file("data\\ne_10m_populated_places_simple.shp")
inter.head(2)
Out[53]:
scalerank natscale labelrank featurecla name namepar namealt diffascii nameascii adm0cap ... pop_other rank_max rank_min geonameid meganame ls_name ls_match checkme min_zoom geometry
0 10 1 8 Admin-1 capital Colonia del Sacramento 0 Colonia del Sacramento 0.0 ... 0 7 7 3443013.0 0 0 9.0 POINT (-57.84000247340134 -34.47999900541754)
1 10 1 8 Admin-1 capital Trinidad 0 Trinidad 0.0 ... 0 7 7 3439749.0 0 0 9.0 POINT (-56.90099656015872 -33.5439989373607)

2 rows × 38 columns

In [54]:
# Getting separate x and y values from the geometry objects contained in the file via the function getPointCoords
def getPointCoords(row, geom, coord_type):
    if coord_type =='x':
        return row[geom].x
    elif coord_type =='y':
        return row[geom].y
In [55]:
# Calculating coordinates for each column:
inter['x'] = inter.apply(getPointCoords,geom='geometry', coord_type='x', axis=1)
inter['y'] = inter.apply(getPointCoords,geom='geometry', coord_type='y', axis=1)
In [56]:
# Drop the geometry column to allow for Bokeh to read the file correctly
inter2 = inter.drop('geometry', axis=1).copy()
inter2.head(2)
Out[56]:
scalerank natscale labelrank featurecla name namepar namealt diffascii nameascii adm0cap ... rank_max rank_min geonameid meganame ls_name ls_match checkme min_zoom x y
0 10 1 8 Admin-1 capital Colonia del Sacramento 0 Colonia del Sacramento 0.0 ... 7 7 3443013.0 0 0 9.0 -57.840002 -34.479999
1 10 1 8 Admin-1 capital Trinidad 0 Trinidad 0.0 ... 7 7 3439749.0 0 0 9.0 -56.900997 -33.543999

2 rows × 39 columns

In [57]:
# Creating the ColumnDataSource object
psource = ColumnDataSource(inter2)
psource
Out[57]:
ColumnDataSource(
id = '08d6d6cc-2435-4537-9734-b6fcbda4ffb0', …)
In [62]:
# Initializing plot figure
p = figure(title="Cities of the World!")
In [65]:
# Adding points to the plot via our ColumnDataSource object
p.circle('x', 'y', source=psource, color='blue', size=1)
Out[65]:
GlyphRenderer(
id = '7474432e-e17b-49f1-a7e8-5e530f78ec51', …)
In [66]:
# File path 
outfp = r"data/point_map2.html"

# Save the map
save(p, outfp)
Out[66]:
'C:\\Users\\nhamler\\Desktop\\665\\Tutorial_GeoPandas\\data\\point_map2.html'
In [67]:
show (p)

b) GeoJSONDataSource

  • Seamless transition to newer GeoJsONDataSource functionality instead of ColumnDataSource
In [20]:
# Importing Sample Dataset included in Bokeh
from bokeh.sampledata.sample_geojson import geojson
In [21]:
# Mapping of sample data using GeoJSONDataSource
geo_source = GeoJSONDataSource(geojson=geojson)

# Initializing figure
p = figure()
p.circle(x='x', y='y', alpha=0.9, source=geo_source) 
Out[21]:
GlyphRenderer(
id = '525b049c-8156-4c0a-aa10-fbe90180b7b8', …)
In [22]:
# Assigning file path
output_file("geojson.html")
show(p)

c) Bokeh and Google Maps

  • Bokeh's GMapPlot supports Googlemaps and enables Bokeh plots to be layered over Google Maps

Creating custom points to add to Google Map

In [23]:
# Import Bokeh functions
from bokeh.io import output_file, show
from bokeh.models import (GMapPlot, GMapOptions, ColumnDataSource, Circle, DataRange1d, PanTool, WheelZoomTool, BoxSelectTool)
In [24]:
# Display options of the Google Map
map_options = GMapOptions(lat=33.74, lng=-84.3880, map_type="roadmap", zoom=11)
In [25]:
# Assigning plot
plot = GMapPlot(
    x_range=DataRange1d(), y_range=DataRange1d(), map_options=map_options)
In [26]:
# Assigning title
plot.title.text = "Atlanta"
In [27]:
# Enter API key obtained from Google
plot.api_key = "AIzaSyASeDwXJrTLdxsgtTfdpUAfMxdtl8mZHZw"
In [28]:
# Creating points to be added to the map
source = ColumnDataSource(
    data=dict(
        lat=[33.74316,33.74319, 33.74314],
        lon=[-84.36, -84.32, -84.39],))
In [29]:
# Initializing Point display options
circle = Circle(x="lon", y="lat", size=15, fill_color="blue", fill_alpha=0.8, line_color=None)
In [30]:
# Adding points and display options to the plot
plot.add_glyph(source, circle)
Out[30]:
GlyphRenderer(
id = 'c802ff50-4ce7-4ede-b98d-283f8507084e', …)
In [31]:
# Add customization tool options for plot display
plot.add_tools(PanTool(), WheelZoomTool(), BoxSelectTool())
# Create file path
output_file("gmap_plot.html")
show(plot)

Adding crime dataset to Google Map:

In [32]:
crime = pd.read_excel("data\COBRADATA2016.xlsx")
crime.head(2)
Out[32]:
MI_PRINX offense_id rpt_date occur_date occur_time poss_date poss_time beat apt_office_prefix apt_office_num ... dispo_code MaxOfnum_victims Shift Avg Day loc_type crimes neighborhood npu x y
0 5637549 150102493 01/10/2016 01/10/2016 22:00:00 01/10/2016 22:00:00 511 NaN NaN ... NaN 1.0 Eve Sun 21.0 BURGLARY-NONRES Downtown M -84.39487 33.75757
1 5641270 150611492 03/01/2016 02/25/2016 12:00:00 02/29/2016 19:00:00 412 NaN NaN ... NaN 1.0 Unk Unk 20.0 LARCENY-NON VEHICLE Vine City L -84.41411 33.75823

2 rows × 23 columns

In [33]:
# Creating dictionary to hold the values for coordinates and point details
crime_source = ColumnDataSource(data=dict(x=crime['x'],
                                      y=crime['y'],
                                      neighborhood=crime['neighborhood'].values,
                                      crimes=crime['crimes'].values,
                                      victims=crime['MaxOfnum_victims'].values))
In [34]:
# Initializing the map options for the google map
map_options = GMapOptions(lat=33.74, lng=-84.3880, map_type="roadmap", zoom=11)
In [35]:
# Creating the GMapPlot based on the Google Map
plot = GMapPlot(
    x_range=DataRange1d(), y_range=DataRange1d(), map_options=map_options)
In [36]:
# Assinging title
plot.title.text = "Atlanta"
In [37]:
# Entering API key to enable Google Map functionality
plot.api_key = "AIzaSyASeDwXJrTLdxsgtTfdpUAfMxdtl8mZHZw"
In [38]:
# Display options for points
circle = Circle(x="x", y="y", size=2.5, fill_color="black", fill_alpha=0.8, line_color=None)
In [39]:
# Adding crime data and display options to the plot
plot.add_glyph(crime_source, circle)
Out[39]:
GlyphRenderer(
id = '33379a2d-5a38-4014-ac94-1420da429f64', …)
In [40]:
plot.add_tools(PanTool(), WheelZoomTool(), BoxSelectTool())
output_file("gmap_plot.html")
In [41]:
show(plot)

d) Hover Tool

Adding the hover tool to display neighborhood, type of crime, and number of victims for each of the points.

In [42]:
# Importing the HoverTool
from bokeh.models import HoverTool
In [43]:
# Initializing the HoverTool and the information to be shown for each point
my_hover = HoverTool()
In [44]:
my_hover.tooltips = [("Crime:","@crimes"), ("Neighborhood:","@neighborhood"), ("No. of victims:", "@victims")]
In [45]:
# Adding the hover tool to the existing map
plot.add_tools(my_hover)
In [46]:
show(plot)